package com.stk.sinous;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Random;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.modifier.AlphaModifier;
import org.andengine.entity.modifier.ParallelEntityModifier;
import org.andengine.entity.modifier.ScaleModifier;
import org.andengine.entity.modifier.SequenceEntityModifier;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.scene.menu.MenuScene;
import org.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.andengine.entity.scene.menu.item.IMenuItem;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.Text.TextOptions;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.HorizontalAlign;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.view.Display;

public class SinousActivity extends SimpleBaseGameActivity implements  IOnSceneTouchListener, IOnMenuItemClickListener{
	
	private Player player;
	private Scene mainScene;
	private int width;
	private int height;
	private Rock[] rocks;
	private int rockWidth; 
	private int rockNumber;
	private MenuScene startScene;
	private Camera camera; 
	private Font font;
	private Text score;
	private int partialMoves;
	private long moves;
	private Text title;
	private Text instructions;
	private Text maxScore;
	private boolean playing;
	
	public EngineOptions onCreateEngineOptions() {
		Display display = getWindowManager().getDefaultDisplay();
		this.width = display.getWidth();
		this.height = display.getHeight();
		
		camera = new Camera(0, 0, width, height);
		
		this.rockWidth = width / 80;		
		this.rockNumber = ((width/(rockWidth*5)) * (height/(rockWidth*5))) / 2;
		
		return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(this.width, this.height), camera);
	}

	public void onCreateResources(){
		Typeface typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
		this.font = FontFactory.create(this.getFontManager(), this.getTextureManager(), 256, 256, TextureOptions.REPEATING_BILINEAR, typeface, 50, true, Color.WHITE);
		this.font.load();
	}

	public Scene onCreateScene(){
		this.mEngine.registerUpdateHandler(new FPSLogger());
		
		/*
		 * 
		 * START SCENE
		 * 
		 */
		this.startScene = new MenuScene(this.camera);
		Rectangle rect = new Rectangle(0, height/4, width, height/2, this.getVertexBufferObjectManager());
		rect.setColor(0/255f,153/255f,204/255f);
		
		title = new Text(this.width/2, this.height/4, font, "Sinuous",250, new TextOptions(HorizontalAlign.CENTER), this.getVertexBufferObjectManager());
		title.setColor(255/255f,255/255f,255/255f);		
		title.registerEntityModifier(new ScaleModifier(0.5f, 1f, (this.width/2)/title.getWidth()));
		title.setPosition(this.width/2 - title.getWidthScaled()/2, this.height/4 + title.getHeightScaled());
		
		instructions = new Text(width/2, height/2 + 50, font, "Avoid red squares and don't stop touching!", 250, new TextOptions(HorizontalAlign.CENTER), this.getVertexBufferObjectManager());
		instructions.setColor(255/255f,255/255f,255/255f);
		instructions.registerEntityModifier(new SequenceEntityModifier(new AlphaModifier(3, 0.0f, 1.0f),new ScaleModifier(0.5f, 1f, (this.width-50)/instructions.getWidth())));
		instructions.setPosition(this.width/2 - instructions.getWidthScaled()/2, (this.height/4)*2 + instructions.getHeightScaled());
		
		maxScore = new Text(width/2, height/2 + 50, font, "Max Score: " + this.loadTopScore(), 250, new TextOptions(HorizontalAlign.CENTER), this.getVertexBufferObjectManager());
		maxScore.setColor(153/255f,204/255f,0/255f);
		maxScore.registerEntityModifier(new SequenceEntityModifier(new AlphaModifier(4, 0.0f, 1.0f),new ScaleModifier(0.5f, 1f, (this.width/3)/maxScore.getWidth())));
		maxScore.setPosition(this.width/2 - maxScore.getWidthScaled()/2, (this.height/4)*3 + maxScore.getHeightScaled());
		
		
		this.startScene.attachChild(rect);
		this.startScene.attachChild(title);
		this.startScene.attachChild(instructions);
		this.startScene.attachChild(maxScore);
		this.startScene.setOnSceneTouchListener(this);
		this.startScene.setBackgroundEnabled(false);
		
		
		
		
		/*
		 * 
		 * MAIN SCENE
		 * 
		 */
		mainScene = new Scene();
		this.mainScene.setOnSceneTouchListener(this);
		mainScene.setBackground(new Background(0f, 0f, 0f));
		
		//this.newGame();			

		mainScene.registerUpdateHandler(new IUpdateHandler() {
			@Override
			public void reset() { }

			@Override
			public void onUpdate(final float pSecondsElapsed) {
				for (Rock rock : rocks){
					if (player.getLastTail() != null){
						if (rock.collidesWith(player.getLastTail())){
							SinousActivity.this.mainScene.setChildScene(SinousActivity.this.startScene, false, true, true);
							SinousActivity.this.gameOver();
						}
					}
				}
			}
		});

		this.mainScene.registerUpdateHandler(new TimerHandler(0.05f, true, new ITimerCallback() {
			@Override
			public void onTimePassed(final TimerHandler pTimerHandler) {
				score.setText("Score: " + SinousActivity.this.moves + "");
			}
		}));

		mainScene.setChildScene(startScene, false, true, true);


		return mainScene;
	}

	@Override
	public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
		
		if (pSceneTouchEvent.isActionDown()){
			this.startScene.back();
			SinousActivity.this.newGame();
		}else if(pSceneTouchEvent.isActionMove()) {
			player.addTail(this, mainScene, (int)pSceneTouchEvent.getX(), (int)pSceneTouchEvent.getY());
			partialMoves++;
			if (partialMoves % 5 == 0){
				moves++;
				partialMoves = 0;
			}
			return true;
		}else if(pSceneTouchEvent.isActionUp()){
			this.mainScene.setChildScene(this.startScene, false, true, true);
			this.gameOver();
		}

		return false;
	}

	@Override
	public boolean onMenuItemClicked(MenuScene pMenuScene, IMenuItem pMenuItem,	float pMenuItemLocalX, float pMenuItemLocalY) {
		this.mainScene.clearChildScene();
		this.startScene.reset();
		return true;
	}
	
	private void newGame(){
		this.mainScene.detachChildren();
		
		moves = 0;			
		
		playing = true;
		
		Random rand = new Random();

		player = new Player(this);	
		
		rocks = new Rock[rockNumber];
		
		for (int i=0; i < rocks.length;i++){
			int realWidth = rand.nextInt(rockWidth) + rockWidth;
			if (rand.nextBoolean()){
				rocks[i] = new Rock(rand.nextInt((int)(width * 1.5f)) - width/2, -rand.nextInt(height/2), realWidth, realWidth, this.getVertexBufferObjectManager(), this.width, this.height, this);
			}else{
				rocks[i] = new Rock(-rand.nextInt(width/2), rand.nextInt((int)(height * 1.5f)) - height/2, realWidth, realWidth, this.getVertexBufferObjectManager(), this.width, this.height, this);
			}
			mainScene.attachChild(rocks[i]);
		}	
		
		score = new Text(width - width/3,10,font,"Score: " + moves,50, this.getVertexBufferObjectManager());
		score.setColor(153/255f,204/255f,0/255f);
		score.registerEntityModifier(new ParallelEntityModifier(
				new AlphaModifier(1.0f, 0f, 1f),
				new ScaleModifier(0.5f, 1f, (this.width/5)/score.getWidth())));
		score.setPosition((this.width/5)*3, 0);
		
		mainScene.attachChild(this.score);	
	}
	
	private void gameOver(){
		if (playing){
			playing=false;
			
			title.setColor(255/255f,255/255f,255/255f);	
			title.setText("GAME OVER");
			title.registerEntityModifier(new ScaleModifier(0.5f, 1f, (this.width/2)/title.getWidth()));
			title.setPosition(this.width/2 - title.getWidthScaled()/2, this.height/4 + title.getHeightScaled());
			
			instructions.setColor(255/255f,255/255f,255/255f);	
			instructions.setText("Touch again to play, and remember, keep touching");
			instructions.registerEntityModifier(new ParallelEntityModifier(new ScaleModifier(0.5f, 1f, (this.width-50)/instructions.getWidth()), new AlphaModifier(3, 0.0f, 1.0f)));
			instructions.setPosition(this.width/2 - instructions.getWidthScaled()/2, (this.height/4)*2 + title.getHeightScaled());
			
			if (moves > loadTopScore()){
				saveTopScore(this.moves);
				maxScore.setText("New max score: " + moves);
			}else{
				maxScore.setText("Max score: " + loadTopScore());
			}
			
			maxScore.setColor(153/255f,204/255f,0/255f);
			maxScore.registerEntityModifier(new ParallelEntityModifier(new AlphaModifier(4, 0.0f, 1.0f),new ScaleModifier(0.5f, 1f, (this.width/3)/maxScore.getWidth())));
			maxScore.setPosition(this.width/2 - maxScore.getWidthScaled()/2, (this.height/4)*3 + maxScore.getHeightScaled());
		}
	}
	
	 public void saveTopScore(long moves2){
    	 String stringScore = "";

    	 try {
    		 stringScore = moves2 +"";
    		 while (stringScore.length() < 20){
    			 stringScore = stringScore + "e";
    		 }
    		 
    		 FileOutputStream fOut;
    		 fOut = this.getBaseContext().openFileOutput("score.dat", Context.MODE_WORLD_READABLE);
    		 OutputStreamWriter osw = new OutputStreamWriter(fOut);
    		 osw.write(stringScore);
    		 osw.flush();
    		 osw.close();
    	 } catch (IOException e) {
    		 e.printStackTrace();
    	 }
     }

     public int loadTopScore(){
    	 try{
    		 FileInputStream fIn = this.getBaseContext().openFileInput("score.dat");
    		 InputStreamReader isr = new InputStreamReader(fIn);
    		 char[] inputBuffer = new char[20];
    		 isr.read(inputBuffer);
    		 String stringScore = new String(inputBuffer);
    		 stringScore = stringScore.replaceAll("e", "");
    		 return Integer.valueOf(stringScore);

    	 } catch (IOException ioe) {    		 
    		 ioe.printStackTrace();
    		 return -1;
    	 }
     }

	public long getMoves() {
		return moves;
	}

	public void setMoves(long moves) {
		this.moves = moves;
	}
	
}